package cn.com.chengmandian.bike.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.*;
import cn.com.chengmandian.bike.dto.WxMiniEncryptedForm;
import cn.com.chengmandian.bike.model.EbMemberInfo;
import cn.com.chengmandian.bike.model.vo.GetOpenIdVo;
import cn.com.chengmandian.bike.pojo.UserCodeInfo;
import cn.com.chengmandian.bike.service.IEbMemberBlackService;
import cn.com.chengmandian.bike.service.IEbMemberInfoService;
import cn.com.chengmandian.bike.utils.WxMiniService;
import cn.com.chengmandian.core.common.constants.CommonConstant;
import cn.com.chengmandian.core.redis.cache.AgentParamCacheService;
import cn.com.chengmandian.core.redis.service.RedisService;
import cn.com.chengmandian.core.web.exceptions.BadResponseException;
import cn.com.chengmandian.core.web.pojo.AgentInfo;
import cn.com.chengmandian.core.web.pojo.AjaxResult;
import cn.com.chengmandian.core.web.pojo.BikeParam;
import cn.com.chengmandian.core.web.utils.LocalMapUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Slf4j
@Api(tags = "微信小程序相关接口")
@RestController
@RequestMapping("/wx/mini")
public class WxMiniController {
    @Autowired
    private WxMiniService wxMiniService;

    @Autowired
    private IEbMemberInfoService memberInfoService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IEbMemberBlackService memberBlackService;

    @Autowired
    private AgentParamCacheService agentParamCacheService;

    private final static String sessionCacheName = "CMD:BIKE:MINI:SESSION:";
    private final static String codeCacheName = "CMD:BIKE:MINI:CODE:";

    @ApiOperation("微信小程序获取openId(无需登录)")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "code", value = "登录code")
    })
    @PostMapping("/openid/get")
    public AjaxResult<GetOpenIdVo> getOpenId(String code) throws Exception {
        GetOpenIdVo vo = new GetOpenIdVo();
        if (StrUtil.isNotEmpty(code)) {
            try {
                WxMaService maService = wxMiniService.getMaServices();
                WxMaJscode2SessionResult result = maService.getUserService().getSessionInfo(code);
                vo.setOpenId(result.getOpenid());
            } catch (Exception e) {
                log.error("getOpenId error Tenant, {}", LocalMapUtil.getAgentInfo() != null ? LocalMapUtil.getAgentInfo().getId() : null);
                log.error("getOpenId error", e);
            }
        } else {
            log.error("getOpenId 缺少code");
        }
        return AjaxResult.success(vo);
    }

    @ApiOperation("微信小程序登录(无需登录)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "登录code")
    })
    @PostMapping("/login")
    public AjaxResult login(String code) throws Exception {
        Assert.isTrue(StrUtil.isNotEmpty(code), "缺少code");
        WxMaJscode2SessionResult result;
        if (redisService.hasKey(codeCacheName + code)) {
            result = (WxMaJscode2SessionResult)redisService.get(codeCacheName + code);
        } else {
            try {
                WxMaService maService = wxMiniService.getMaServices();
                result = maService.getUserService().getSessionInfo(code);
                redisService.set(codeCacheName + code, result, 60 * 60);
            } catch (WxErrorException e) {
                AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
                log.error("wxlogin error:agentId=" + agentInfo.getId(), e);
                throw e;
            }
        }
        EbMemberInfo memberInfo = memberInfoService.getByOpenId(result.getOpenid());
        if (memberInfo != null) {
            Assert.isTrue(memberInfo.getIsEnabled().equals(CommonConstant.ONE), "账号已被禁用");
            String token = memberInfoService.getToken(memberInfo);
            Map res = MapUtil.of("token", token);
            res.put("openId", result.getOpenid());
            redisService.set(sessionCacheName + result.getOpenid(), result.getSessionKey(), 60 * 60);
            return AjaxResult.success(res);
        }
        redisService.set(sessionCacheName + result.getOpenid(), result.getSessionKey(), 60 * 60);
        return AjaxResult.success(MapUtil.of("openId", result.getOpenid()));
    }

    @ApiOperation("通过手机号登陆(无需登录)")
    @PostMapping("/phone/login")
    public AjaxResult loginByPhone(@RequestBody WxMiniEncryptedForm wxMiniEncryptedForm) throws Exception {
        WxMaService maService = wxMiniService.getMaServices();
        String sessionKey = (String)redisService.get(sessionCacheName + wxMiniEncryptedForm.getOpenId());
        Assert.isTrue(StrUtil.isNotBlank(sessionKey), "缺少sessionKey");
        Assert.isTrue(StrUtil.isNotBlank(wxMiniEncryptedForm.getEncryptedData()), "缺少EncryptedData");
        Assert.isTrue(StrUtil.isNotBlank(wxMiniEncryptedForm.getIv()), "缺少Iv");
        WxMaPhoneNumberInfo phoneInfo = maService.getUserService().getPhoneNoInfo(sessionKey, wxMiniEncryptedForm.getEncryptedData(), wxMiniEncryptedForm.getIv());
        String phone = phoneInfo.getPhoneNumber();
        Assert.isTrue(StrUtil.isNotEmpty(phone), "未获取到手机号");
        if (phone.length() != 11) {
            phone = phone.replace("+", "");
            phone = phone.replace("-", "");
            if (phone.startsWith("86") && phone.length() == 13) {
                phone = phone.substring(2);
            }
            if (phone.length() != 11) {
                log.error("用户手机号长度不对：{}", phone);
                throw new BadResponseException("手机号不合规");
            }
        }
        EbMemberInfo memberInfo = memberInfoService.getByPhone(phone);
        //判断手机号是否拉黑
        memberBlackService.checkPhone(phone);
        AgentInfo agentInfo = LocalMapUtil.getAgentInfo();
        if (memberInfo != null) {
            Assert.isTrue(memberInfo.getIsEnabled().equals(CommonConstant.ONE), "账号已被禁用");
            // 检验身份证号
            if(StrUtil.isNotBlank(memberInfo.getIdCard())){
                memberBlackService.checkIdCard(memberInfo.getIdCard());
            }
            // 没有openid或者openid不相同
            if (StrUtil.isBlank(memberInfo.getOpenId()) || !memberInfo.getOpenId().equals(wxMiniEncryptedForm.getOpenId())) {
                memberInfoService.updateOpenId(memberInfo.getId(), wxMiniEncryptedForm.getOpenId());
            }
        } else {
            BikeParam bikeParam = agentParamCacheService.getParam(agentInfo.getId());
            if (bikeParam.getUserAgentRegisterAuthEnabled() != null && bikeParam.getUserAgentRegisterAuthEnabled()) {
                UserCodeInfo userCodeInfo = new UserCodeInfo().setMobile(phone).setAreaId(agentInfo.getAreaId()).setOpenId(wxMiniEncryptedForm.getOpenId());
                String userCode = StrUtil.uuid();
                redisService.set("CMD:BIKE:"+ agentInfo.getId() + ":USERCODE:" + userCode, userCodeInfo, 60 * 60 * 3);
                JSONObject data = new JSONObject();
                data.put("userCode", userCode);
                throw new BadResponseException(501, "请先实名认证", data);
            }
            memberInfo = memberInfoService.createMember(agentInfo.getAreaId(), phone, wxMiniEncryptedForm.getOpenId(), null, null);
        }
        String token = memberInfoService.getToken(memberInfo);
        return AjaxResult.success(MapUtil.of("token", token));
    }
}
